// usercenter/internal/verification/manager.go
package verification

import (
	"errors"
	"fmt"
	"math/rand"

	"github.com/zeromicro/go-zero/core/stores/redis"
)

const (
	vCodePrefix     = "vcode:"      // 验证码存储
	vCodeTimePrefix = "vcode_time:" // 发送时间记录
)

type VerificationManager struct {
	redis *redis.Redis
	email EmailSender // 邮件发送接口
}

type EmailSender interface {
	SendVerificationEmail(email, code string) error
	ForwardFeedbackToAdmin(userid, username, userconnect, feedbackContent string) error
}

func NewVerificationManager(rds *redis.Redis, sender EmailSender) *VerificationManager {
	return &VerificationManager{
		redis: rds,
		email: sender,
	}
}

// GenerateVerificationCode 生成并发送验证码
func (m *VerificationManager) GenerateVerificationCode(email string) error {
	// 1. 频率控制检查
	timeKey := vCodeTimePrefix + email
	// 使用SETNX原子操作确保并发安全
	success, err := m.redis.SetnxEx(timeKey, "1", 60)
	if err != nil {
		return fmt.Errorf("redis操作失败: %v", err)
	}
	if !success {
		return errors.New("操作过于频繁，请1分钟后再试")
	}

	// 2. 生成6位数字验证码
	// rand.Seed(time.Now().UnixNano())
	// code := fmt.Sprintf("%06d", rand.Intn(1000000))
	// 使用示例
	code := generateRandomCode(6) // 生成6位随机字母数字组合

	// 3. 存储验证码(30分钟有效)
	vcodeKey := vCodePrefix + email
	if err := m.redis.Setex(vcodeKey, code, 1800); err != nil {
		return fmt.Errorf("验证码存储失败: %v", err)
	}

	// 4. 发送邮件
	if err := m.email.SendVerificationEmail(email, code); err != nil {
		return fmt.Errorf("邮件发送失败: %v", err)
	}

	return nil
}

func generateRandomCode(length int) string {
	// 定义字符集：10个数字
	const charset = "0123456789"
	// 创建字节切片
	b := make([]byte, length)
	// 从字符集中随机选取字符
	for i := range b {
		b[i] = charset[rand.Intn(len(charset))]
	}
	return string(b)
}

// VerifyCode 验证验证码有效性
func (m *VerificationManager) VerifyCode(email, code string) (bool, error) {
	vcodeKey := vCodePrefix + email

	// 获取存储的验证码
	storedCode, err := m.redis.Get(vcodeKey)
	if err != nil {
		if err == redis.Nil {
			return false, errors.New("验证码已过期或不存在")
		}
		return false, fmt.Errorf("redis操作失败: %v", err)
	}

	// 验证码比对
	if storedCode != code {
		return false, errors.New("验证码不匹配")
	}

	// 验证成功后删除验证码
	if _, err := m.redis.Del(vcodeKey); err != nil {
		return false, fmt.Errorf("验证码删除失败: %v", err)
	}

	return true, nil
}
